package com.example.vueblog.aspect;

import com.alibaba.fastjson.JSON;
import com.example.vueblog.annotation.Log;
import com.example.vueblog.common.enums.BusinessStatusEnum;
import com.example.vueblog.common.enums.BusinessTypeEnum;
import com.example.vueblog.common.utils.ApplicationContextUtils;
import com.example.vueblog.common.utils.SecurityUtils;
import com.example.vueblog.common.utils.ServletUtils;
import com.example.vueblog.entity.Logs;
import com.example.vueblog.entity.security.SelfUserDetails;
import com.example.vueblog.service.LogsService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerMapping;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;

/**
 * 日志切面类
 *
 * @author yushunshun
 * @date 2022/7/10 1:01
 */
@Component
@Aspect //表示该类是一个切面类
@Slf4j
public class LogAspect {

    /**
     * 方法返回处理
     *
     * @param jp         连接点
     * @param log        注解
     * @param jsonResult 返回对象
     */
    @AfterReturning(value = "@annotation(log)", returning = "jsonResult")
    public void afterReturning(JoinPoint jp, Log log, Object jsonResult) {
        handleLog(jp, log, jsonResult, null);
    }

    /**
     * 方法异常处理
     *
     * @param jp  连接点
     * @param log 注解
     * @param e   异常
     */
    @AfterThrowing(value = "@annotation(log)", throwing = "e")
    public void afterReturning(JoinPoint jp, Log log, Exception e) {
        handleLog(jp, log, null, e);
    }

    /**
     * 统一处理
     *
     * @param jp         连接点
     * @param logAnnotation        注解
     * @param jsonResult 返回对象
     * @param e          异常
     */
    private void handleLog(JoinPoint jp, Log logAnnotation, Object jsonResult, Exception e) {

        try {
            /*操作数据库日志*/

            //创建操作对象类型
            Logs logs = new Logs();
            //标题
            String title = logAnnotation.title();
            if (!StringUtils.isEmpty(title)) logs.setTitle(title);
            //业务类型
            BusinessTypeEnum businessTypeEnum = logAnnotation.businessType();
            logs.setBusinessType(businessTypeEnum.ordinal());
            //获取方法全类名
            String class_name = jp.getTarget().getClass().getName();
            String method_name = jp.getSignature().getName();
            logs.setMethod(class_name + "." + method_name + "()");
            //请求方式
            logs.setRequestMethod(ServletUtils.getRequest().getMethod());
            //操作人
            SelfUserDetails userDetails = SecurityUtils.getUser();
            if (userDetails != null) logs.setOperName(userDetails.getUsername());
            //uri
            logs.setOperUrl(ServletUtils.getRequest().getRequestURI());
            //请求参数
            Object[] args = jp.getArgs();
            logs.setOperParam(JSON.toJSONString(args));
            //状态
            if (e != null) {
                logs.setStatus(BusinessStatusEnum.FAIL.ordinal());
            } else {
                logs.setStatus(BusinessStatusEnum.SUCCESS.ordinal());
            }
            //操作时间
            logs.setOperTime(LocalDateTime.now());

            //获取日志service
            LogsService logsService = (LogsService) ApplicationContextUtils.getBean("logsServiceImpl");
            logsService.getBaseMapper().insert(logs);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==日志通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    /**
     * 获取请求的参数，放到log中
     *
     * @param logs 操作日志
     * @throws Exception 异常
     */
    /*private void setRequestValue(JoinPoint joinPoint, Logs logs ) throws Exception
    {
        String requestMethod = logs.getRequestMethod();
        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
        {
            String params = argsArrayToString(joinPoint.getArgs());
            logs.setOperParam(StringUtils.substring(params, 0, 2000));
        }
        else
        {
            Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
        }
    }*/
}
